#pragma once
#include <iostream>
#include <unistd.h>
#include <sstream>
#include <fstream>
#include <string>
#include <ctime>
#include <chrono>
#include <iomanip>
#include <filesystem> //c++17
#include "Mutex.hpp"
namespace LogModle
{
    using namespace Mutex;
    const std::string defaultpath = "./log";
    const std::string defaultname = "log.txt";
    enum class LogLever
    {
        DEBUG,
        INFO,
        WARNING,
        ERROR,
        FATAL
    };
    std::string LeverToString(LogLever lever)
    {
        switch (lever)
        {
        case LogLever::DEBUG:
            return "DEBUG";
        case LogLever::INFO:
            return "INFO";
        case LogLever::WARNING:
            return "WARNING";
        case LogLever::ERROR:
            return "ERROR";
        case LogLever::FATAL:
            return "FATAL";
        default:
            return "UNKNOWN";
        }
    }
    std::string GetCurTimeAndToString(const std::string &formant = "%Y-%m-%d %H:%M:%S")
    {
        auto now = std::chrono::system_clock::now();
        std::time_t time = std::chrono::system_clock::to_time_t(now);
        std::tm *local_time = std::localtime(&time);
        std::stringstream ss;
        ss << std::put_time(local_time, formant.c_str());
        return ss.str();
    }

    class LogStrategy
    {
    public:
        virtual ~LogStrategy() = default;
        virtual void SyncLog(const std::string &message) = 0;
    };
    // 向显示器打印
    class ConsoleLogStrategy : public LogStrategy
    {
    public:
        void SyncLog(const std::string &message)
        {
            LockGuard lock(_mutex);
            std::cout << message << std::endl;
        }

    private:
        MyMutex _mutex;
    };

    // 向文件打印
    class FileLogStrategy : public LogStrategy
    {
    public:
        FileLogStrategy(const std::string path = defaultpath, const std::string name = defaultname)
            : _log_path(path),
              _log_name(name)
        {
            LockGuard lock(_mutex); //???????为什么加锁   访问了临界资源
            if (std::filesystem::exists(_log_path))
                return;
            try
            {
                std::filesystem::create_directories(_log_path);
            }
            catch (const std::exception &e)
            {
                std::cerr << e.what() << '\n';
            }
        }
        void SyncLog(const std::string &message) override
        {
            LockGuard lock(_mutex);
            std::string log = _log_path + (_log_path.back() == '/' ? "" : "/") + _log_name;
            std::ofstream fout(log.c_str(), std::ios::app); // 追加信息
            if(!fout.is_open())
            {
                return ;
            }
            fout << message << std::endl;
            fout.close();
        }

    private:
        MyMutex _mutex;
        std::string _log_path;
        std::string _log_name;
    };
    class Logger
    {
    public:
        Logger()
        {
            UseConsoleLogStrategy(); // 默认使用显示器策略
        }
        ~Logger()
        {
        }
        void UseConsoleLogStrategy()
        {
            _Strategy = std::make_unique<ConsoleLogStrategy>();
        }
        void UseFileLogStrategy()
        {
            _Strategy = std::make_unique<FileLogStrategy>();
        }
        class LogMassage
        {
        public:
            LogMassage(LogLever lever, std::string name, int line, Logger &logger)
                : _name(name),
                  _lever(lever),
                  _line(line),
                  _logger(logger)
            {
                _cur_time = GetCurTimeAndToString();
                _pid = getpid();
                std::stringstream ss;
                ss << "[" << _cur_time << "] "
                   << "[" << LeverToString(_lever) << "] "
                   << "[" << _pid << "] "
                   << "[" << _name << "] "
                   << "[" << _line << "]"
                   << "-    ";
                _info = ss.str();
            }

            template <typename T>
            LogMassage& operator<<(const T &data)
            {
                std::stringstream ss;
                ss << data;
                _info += ss.str();
                return *this;
            }
            ~LogMassage()
            {
                if(_logger._Strategy)
                {
                    _logger._Strategy->SyncLog(_info);
                }

            }
        private:
            std::string _cur_time;
            LogLever _lever; // 等级
            pid_t _pid;
            std::string _name;
            int _line; // 行号
            std::string _info;
            Logger &_logger; // 方便刷新日志
        };
        LogMassage operator()(LogLever lever, std::string name, int line) // 刷新日志
        {
            return LogMassage(lever, name, line, *this);
        }

    private:
        std::unique_ptr<LogStrategy> _Strategy;
    };
    Logger logger;
    #define LOG(type) logger(type,__FILE__,__LINE__)

    #define ENABLE_CONSOLE_LOG_STRATERY logger.UseConsoleLogStrategy()
    #define ENABLE_FILE_LOG_STRATERY logger.UseFileLogStrategy()
}